package com.dmatek.uwb.packet.ianalysis.handler;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.dmatek.uwb.local.algorithm.ILocalAlgorithm;
import com.dmatek.uwb.packet.bean.AssistLocation;
import com.dmatek.uwb.packet.bean.ENodeBDistance;
import com.dmatek.uwb.packet.bean.FilterTagInfor;
import com.dmatek.uwb.packet.bean.TagInfor;
import com.dmatek.uwb.packet.ianalysis.callback.IReportCallBack;
import com.dmatek.uwb.util.tool.AnalyticalUtil;
import com.dmatek.uwb.xml.dom.bean.BaseNode;
/**   
 * 用于解析卡片数据包
 * @author zhangfu  
 * @date 2019年12月3日 下午1:50:26 
 * @version V1.0   
 */
public class TagReportHandler extends  BaseAnalysisPackHandler {
	// 卡片上报讯息的Map
	private Map<String, TagInfor> tagsMap = null;
	// 基站位置讯息的Map
	private Map<String, BaseNode> nodesMap = null;
	// 卡片回调函数
	private IReportCallBack<TagInfor> iTagReportCallBack;
	// 定位算法
	private ILocalAlgorithm<TagInfor, AssistLocation> iLocalAlgorithm;
	public TagReportHandler(IReportCallBack<TagInfor> iTagReportCallBack, ILocalAlgorithm<TagInfor, AssistLocation> iLocalAlgorithm, 
			Map<String, BaseNode> nodesMap) {
		super();
		// 创建初始容器
		this.tagsMap = new ConcurrentHashMap<String, TagInfor>(AnalyticalUtil.INITIAL_CAPACITY);
		this.iTagReportCallBack = iTagReportCallBack;
		this.iLocalAlgorithm = iLocalAlgorithm;
		this.nodesMap = nodesMap;
	}
	@Override
	public boolean templateMethod(byte[] temps, int limit,
			InetSocketAddress sendAddress, int index) throws Exception {
		short cs = 0;
		String strTagId = "";
 		if(temps.length < index + AnalyticalUtil.TAG_PACK_NUM_PLACE + 1) {
			return false;
		}
		int length = index + AnalyticalUtil.TAG_STILL_SIZE + temps[index + AnalyticalUtil.TAG_PACK_NUM_PLACE] * 4 + 1;
		if(temps.length < length) {
			return false;
		}
		if(temps[index + 1] == AnalyticalUtil.TAG_STILL_TYPE && temps[length - 1] == AnalyticalUtil.END) {
             /*  
             *   FC(0) + 03(1) + SerialNum[1 byte](2) + 
             *   LocateType[1 byte](3) + TagId[2 byte](4-5) + 
             *   Battery[1 byte](6) + GsensorTime[2 byte](7-8) + 
             *   TagSleepTime[2 byte](9-10) +  GsensorX[2byte](11-12) + GsensorY[2byte](13-14) + GsensorZ[2byte](15-16)  + 
             *   RouterNum[1 byte](17) + 
             *   RouterId1[2 byte](18-19) + Distance1[2 byte](20-21) + 
             *   ... + CS + FB
             * */
			// 数据包的长度(从0开始)
			int total = index + AnalyticalUtil.TAG_STILL_SIZE + temps[index + AnalyticalUtil.TAG_PACK_NUM_PLACE] * 4;
			// 计算校验和
			for(int i = index, size = total - 1; i < size; i++) {
				cs += temps[i];
			}
			// 去掉左侧bit(数据位)超出部分
			cs &= 0xFF;
			if((byte)cs == temps[total - 1]) {
				strTagId = String.format("%02X%02X", temps[index + 4], temps[index + 5]);
				if (tagsMap.containsKey(strTagId)) {
					TagInfor taginfor = tagsMap.get(strTagId);
					if (null != taginfor) {
						if (taginfor.getIndex() != (int)(temps[index + 2] & 0xFF)) {
							// 清除当前卡片讯息中的基站距离容器项
							taginfor.geteNodeBDistances().clear();
							ENodeBDistance eNodeBDistance = null;
							for (int i = 0; i < temps[index + AnalyticalUtil.TAG_PACK_NUM_PLACE]; i ++) {
								eNodeBDistance = new ENodeBDistance();
								byte[] tId = new byte[2];
								System.arraycopy(temps, index + AnalyticalUtil.TAG_PACK_NUM_PLACE + 1 + i * 4, tId, 0, 2);
								String stRd = String.format("%02X%02X", tId[0], tId[1]);
								eNodeBDistance.setId(stRd);
								// 判断当前的定位类型
								int dis = (int) ((temps[index + AnalyticalUtil.TAG_PACK_NUM_PLACE + 3 + i * 4] & 0xFF) << 8 | 
										(temps[index + AnalyticalUtil.TAG_PACK_NUM_PLACE + 4 + i * 4] & 0xFF));
								if(null != nodesMap) {
									BaseNode node = nodesMap.get(stRd);
									if(null != node) {
										if(node.getHeight() < dis) {
											eNodeBDistance.setDistance((float) Math.sqrt(dis * dis - node.getHeight() * node.getHeight()));
										} else {
											eNodeBDistance.setDistance(AnalyticalUtil.MIN_DISTANCE);
										}
									} else {
										eNodeBDistance.setDistance(dis);
									}
								} else {
									eNodeBDistance.setDistance(dis);
								}
								eNodeBDistance.setPriority((byte) i);
								taginfor.geteNodeBDistances().put(stRd, eNodeBDistance);
							}
						} else { // 说明是同一包数据,它的基站信息相同的，所以不用处理

						}
						taginfor.setSos(temps[index + 3]);
						taginfor.setAdc(temps[index + 6]);
						taginfor.setTotalBasicNum(temps[index + 11 + 6]);
						taginfor.setIndex((int)(temps[index + 2] & 0xFF));
						taginfor.setNoExeTime((int) ((temps[index + 7] & 0xFF) << 8 | (temps[index + 8] & 0xFF)));
						// 设置Sensor的移动时间, 0: 静止; 1:移动;
						if (taginfor.getNoExeTime() > 0) {// 没有移动(静止)
							taginfor.setSensor(0);
						} else {// 有移动
							taginfor.setSensor(1);
						}
						taginfor.setSleepTime((int) ((temps[index + 9] & 0xFF) << 8 | (temps[index + 10] & 0xFF)));
						taginfor.setUpload(System.currentTimeMillis());
						taginfor.setGsensorX((short) ((temps[index + 11] & 0xFF) << 8 | (temps[index + 12] & 0xFF)));
						taginfor.setGsensorY((short) ((temps[index + 13] & 0xFF) << 8 | (temps[index + 14] & 0xFF)));
						// 计算卡片坐标
						AssistLocation assistLocal = null;
						if(null != iLocalAlgorithm) {
							assistLocal = iLocalAlgorithm.calculatePosition(taginfor);
						}
						if (null != assistLocal && null != assistLocal.getPlace()
						&& (assistLocal.getPlace().getX() > 0 || assistLocal.getPlace().getY() > 0)) {
							taginfor.setX(assistLocal.getPlace().getX());
							taginfor.setY(assistLocal.getPlace().getY());
						}
						if(null != iTagReportCallBack) {
							iTagReportCallBack.callBack(taginfor);
						}
					}
				} else {
					TagInfor taginfor = new FilterTagInfor();
					byte[] id = new byte[2];
					System.arraycopy(temps, index + 4, id, 0, 2);
					taginfor.setId(String.format("%02X%02X", id[0], id[1]));
					for (int i = 0; i < temps[index + AnalyticalUtil.TAG_PACK_NUM_PLACE]; i ++) {
						ENodeBDistance eNodeBDistance = new ENodeBDistance();
						byte[] tid = new byte[2];
						System.arraycopy(temps, index + AnalyticalUtil.TAG_PACK_NUM_PLACE + 1 + i * 4, tid, 0, 2);
						String stRd = String.format("%02X", tid[0])
								+ String.format("%02X", tid[1]);
						eNodeBDistance.setId(stRd);
						// 判断定位方式
						int dis = (int) ((temps[index + AnalyticalUtil.TAG_PACK_NUM_PLACE + 3 + i * 4] & 0xFF) << 8
								| (temps[index + AnalyticalUtil.TAG_PACK_NUM_PLACE + 4 + i * 4] & 0xFF));
						if(null != nodesMap) {
							BaseNode node = nodesMap.get(stRd);
							if(null != node) {
								if(node.getHeight() < dis) {
									eNodeBDistance.setDistance((float) Math.sqrt(dis * dis - node.getHeight() * node.getHeight()));
								} else {
									eNodeBDistance.setDistance(AnalyticalUtil.MIN_DISTANCE);
								}
							} else {
								eNodeBDistance.setDistance(dis);
							}
						} else {
							eNodeBDistance.setDistance(dis);
						}
						eNodeBDistance.setPriority((byte) i);
						taginfor.geteNodeBDistances().put(stRd, eNodeBDistance);
					}
					taginfor.setUpload(System.currentTimeMillis());
					taginfor.setSos(temps[index + 3]);
					taginfor.setAdc(temps[index + 6]);
					taginfor.setTotalBasicNum(temps[index + 11 + 6]);
					taginfor.setIndex((int)(temps[index + 2] & 0xFF));
					taginfor.setNoExeTime((int) ((temps[index + 7] & 0xFF) << 8 | (temps[index + 8] & 0xFF)));
					// 设置Sensor的移动时间,//0: 静止；1:移动
					if (taginfor.getNoExeTime() > 0) { // 没有移动(静止)
						taginfor.setSensor(0);
					} else {	// 有移动
						taginfor.setSensor(1);
					}
					taginfor.setSleepTime((int) ((temps[index + 9] & 0xFF) << 8 | (temps[index + 10] & 0xFF)));
					taginfor.setGsensorX((short) ((temps[index + 11] & 0xFF) << 8 | (temps[index + 12] & 0xFF)));
					taginfor.setGsensorY((short) ((temps[index + 13] & 0xFF) << 8 | (temps[index + 14] & 0xFF)));
					// 计算卡片坐标
					AssistLocation assistLocal = null;
					if(null != iLocalAlgorithm) {
						assistLocal = iLocalAlgorithm.calculatePosition(taginfor);
					}
					if(null != assistLocal && null != assistLocal.getPlace() 
					&& (assistLocal.getPlace().getX() > 0 || assistLocal.getPlace().getY() > 0)) {
						taginfor.setX(assistLocal.getPlace().getX());
						taginfor.setY(assistLocal.getPlace().getY());
					}
					if(null != iTagReportCallBack) {
						iTagReportCallBack.callBack(taginfor);
					}
					tagsMap.put(strTagId, taginfor);
				}
				return true;
			}
		}
		return false;
	}
	@Override
	public byte getPacketHeader() {
		return AnalyticalUtil.HEAD;
	}
	public Map<String, TagInfor> getTagsMap() {
		return tagsMap;
	}
	@Override
	public int getPacketSize() {
		return AnalyticalUtil.TAG_STILL_SIZE + 1;
	}
}
